/***************************************************************************************************
  *Copyright(C),2010-2016,Sumscope
  *FileName	:  pinyin.h
  *Author	:  scofined.qi
  *Version	:  1.0
  *Date		:  2015/12/22
  *Desc		:  //用于主要说明此程序文件完成的主要功能
  *Relation :  
  *Others	:  //其他内容说明
  *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
  *History	:  //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
***************************************************************************************************/
#pragma once
#include "../container/CHashMap.h"
#include "../strings/simple_array.h"
#include "../strings/string_convert.h"
#include "../pointer/scoped_pointer.h"
#include "../core.h"
#include <map>

namespace qb{
namespace base{
	namespace pinyin{
		struct HanziInfo;
		enum {
			PINYIN_MAX_BUFLENGTH	= 4096
		};
	}
    class S_CORE_EXPORT SpellBufBuilderImpl{
		int			m_count;			// 有多少个拼音
		int			m_length;			// 总共占有字符长度
		int			m_capcity;	
		wchar_t*	m_buffer;	// 缓冲区
	public:
		SpellBufBuilderImpl(wchar_t* buf, int capcity);
		void Reset();
		void AddStart(wchar_t c);
		void AddString(const wchar_t* str, int len);
		void AddString(wchar_t str);
		const wchar_t* GetBuf()const{ return m_buffer; }
		wchar_t* GetBuf(){ return m_buffer; }
		int GetLength()const{return m_length;}
		int GetCapcity()const{ return m_capcity; }
	};

	//--------------------------------------------------------------------------
	// 在指定缓冲区中增加汉字拼音字符串
	//--------------------------------------------------------------------------
	template<int N>
    class S_CORE_EXPORT SpellBufBuilder : public SpellBufBuilderImpl{
		wchar_t		m_real_buffer[N];		// 缓冲区
	public:
		SpellBufBuilder():SpellBufBuilderImpl(m_real_buffer,N){}
	};
	class SpellMatch;
    class S_CORE_EXPORT SpellManager{
	public:
		enum {
			MAX_SPELL_LEN	= 10,			// 拼音字符串的最大长度
			MAX_HANZI_LEN	= 4,			//
			MAX_SPELL_COUNT = 8				// 多音字的拼音最大个数
		};
		typedef struct { wchar_t	data[MAX_SPELL_LEN]; }tSpell;
		struct tHanzi{
			wchar_t	code;
			//unsigned char data[MAX_HANZI_LEN];
		bool operator==(const tHanzi& hz)const{return code==hz.code;}
		};
		class tHanziHasher{
		public:
			unsigned int operator()(const tHanzi& hz)const{
				return (unsigned int)hz.code;
			}
		};
		class WCharHasher{
		public:
			unsigned int operator()(const wchar_t& hz)const{
				return (unsigned int)hz;
			}
		};
		typedef SFixedArray<int,MAX_SPELL_COUNT> tSpellIds;
        struct S_CORE_EXPORT SpellInfo{
			char	tone;			// 1,2,3,4,5
			char	len;			//
			tSpell	name;			//
		};
		class SpellContext{
            typedef std::map<wchar_t, int> WCharIntMap;
			wchar_t				m_code;		// 当前多音字
			WCharIntMap			m_prefix;	// 前后相关的汉字
			WCharIntMap			m_post;	// 前后相关的汉字
		public:
			SpellContext(wchar_t code) :m_code(code){}
			void AddPrefix(wchar_t prefix,int index)
			{
				m_prefix.insert(WCharIntMap::value_type(prefix, index));
			}
			void AddPost(wchar_t post, int index)
			{
				m_post.insert(WCharIntMap::value_type(post, index));
			}
			bool GetSpellByPrefix(wchar_t prefix, int& index)
			{
				WCharIntMap::iterator it = m_prefix.find(prefix);
				if (it != m_prefix.end())
				{
					index = it->second;
					return true;
				}
				return false;
			}
			bool GetSpellByPost(wchar_t post, int& index){
				WCharIntMap::iterator it = m_post.find(post);
				if (it != m_post.end())
				{
					index = it->second;
					return true;
				}
				return false;
			}
		};
		typedef CHashMap<wchar_t, SpellContext*, WCharHasher> SpellContextMap;
		typedef CHashMap<tHanzi, tSpellIds, tHanziHasher> HanziSpellMap;
	private:
		SimpleArray<SpellInfo>*		m_spells;
		HanziSpellMap*				m_spellid_map;
		SpellContextMap*			m_prefixmap;
		unsigned char				m_link_char;
		SpellBufBuilder<pinyin::PINYIN_MAX_BUFLENGTH>		m_all_builder;
		SpellBufBuilder<pinyin::PINYIN_MAX_BUFLENGTH>		m_short_builder;
		SpellMatch*					m_spell_matcher;
		bool						m_ignore_tone;
		CConvertFast				m_convert;
		bool						m_use_context;
		bool						m_spell_capital;
	public:
		SpellManager();
		~SpellManager();
		static int UnitTest();

		void SetUseContext(bool useContext){ m_use_context = useContext; }
		void LoadDict(const BaseString& fullDictFile);
		void LoadDict(const wchar_t* utf8Array, int size);
		void LoadDefaultDict();
		bool ExportDict(const BaseString& fullDictFile);


		int GetLastMatchPos()const;



		/*
		
			text
			tlen
			key
			klen
			full
			checkcn
		*/
		bool IsMatchPinyin(const wchar_t* text, int tlen, const wchar_t* key, int klen, bool full, bool checkcn);
		bool IsAlignMatchPinyin(const wchar_t* text, int tlen, const wchar_t* key, int klen);


		bool GetAllSpellForString(const wstring& szStr, wstring& spell, wstring& shortSpell);


		void GetPinyin(const wchar_t* buffer, wstring &sJianpin, wstring &sQuanpin);


		bool GetSpell(const wchar_t* text, int tlen, wchar_t* fullspell, int& flen, wchar_t* shortspell, int& slen);


		/*
			找出str中的多音字汉字,将其逐个追加到polyCharacters中
		*/
		void GetPolySpell(const wstring& str, wstring& polyCharacters);


		/*
			找出汉字code的所有拼音,以逗号分割
		*/
		int GetSpellString(wchar_t code, wstring& spell);
		int GetSpellStringWithContext(wchar_t code,wchar_t prev,wchar_t next, wstring& spell);


		void Dump();

		/*
			根据前后汉字,计算汉字code的所有可能的拼音,将其放在ids中
			code:指定的汉字
			ids:获取汉字的所有拼音信息
			full:指定是需要汉字的拼音的全部英文字母,还是需要拼音的第一个英文字符
			prev:文本串中前一个汉字,用于根据多音字修正信息m_prefixmap过滤掉不用的拼音
			next:文本串中后一个汉字,用于根据多音字修正信息m_prefixmap过滤掉不用的拼音
		*/
		bool GetSpellIdEx(wchar_t code, tSpellIds& ids, bool full,wchar_t prev,wchar_t next);


		/*
			获取指定汉字的所有拼音信息的索引
			code:指定的汉字
			ids:返回的该汉字的所有拼音的索引
		*/
		bool GetSpellId(wchar_t code, tSpellIds& ids);

		/*
			根据拼音索引获取拼音信息
		*/
		const SpellInfo& GetSpellInfo(int id)const{return m_spells->at(id);}
	protected:
		int GetSpellIdByName(const tSpellIds& ids, const wchar_t* spell, int len);

		int SplitIntoHanziArray(const wchar_t* wstr,pinyin::HanziInfo* parray,int capcity);
		void AddSpellLine(const char* linestr, int len, int i, bool isutf8);

		void AddPrefixLine(const wchar_t* line,int len=0);
		void AddPrefixLineImpl(const wchar_t* line, int len = 0);
		void AddDefaultPrefixLines();
	};

    class S_CORE_EXPORT Spell{
	public:
		static void Parse(const wchar_t* buffer, int len, wchar_t* quanbuf, int& quanlen, wchar_t* jianbuf, int& jianlen);
		static void ParseEx(const unsigned short* buffer, int len, unsigned short* quanbuf, int& quanlen, unsigned short* jianbuf, int& jianlen);
		static bool IsAlignMatchPinyin(const unsigned short* text, int tlen, const unsigned short* key, int klen);
		static bool IsMatchPinyin(const wchar_t* text, int tlen, const wchar_t* key, int klen, bool full, bool checkcn);

	};
}//namespace base;
}//namespace qb;
